package main

import (
	"fmt"
	"reflect"
)

// 在 Go 中，range 关键字用于 for 循环迭代字符串(string)、数组(array)、切片(slice)、通道(channel)或映射集合(map)中的元素。
func main() {
	traverseStr("a1中文")
	var arr = [5]int{1, 2}
	var sli = make([]int, 2, 5)
	traverseStr("a1中文")
	traverseArr(arr)
	traverseSli(sli)

	ch := make(chan int, 10)
	traverseChannel(ch)

	m := map[string]string{
		"name": "张佳伟",
		"age":  "32",
	}
	traverseMap(m)
}

// 在Go语言中，汉字占3个字节，输出的字符对应Unicode 的值，所以value输出的是数字,使用%c能输出实际的字符
func traverseStr(str string) {
	fmt.Println("使用 range 遍历字符串（输出 Unicode 值）：")
	for index := range str {
		fmt.Printf("index: %d, unicode value: %v, value: %c\n", index, str[index], str[index])
	}

	fmt.Println("\n使用 range 遍历字符串（输出字符）：")
	for index, value := range str {
		fmt.Printf("index: %d, unicode value: %v, value: %c\n", index, value, value)
	}
}

// 遍历数组
func traverseArr(arr [5]int) {
	for index := range arr {
		fmt.Printf("index : %d,value : %d\n", index, arr[index])
	}
	for index, value := range arr {
		fmt.Printf("index : %d,value : %d\n", index, value)
	}
}

// 遍历数组
func traverseSli(sli []int) {
	fmt.Println(reflect.TypeOf(sli))
	// 方法1：只拿到数组的下标索引
	for index := range sli {
		fmt.Printf("slice index : %d,value : %d\n", index, sli[index])
	}
	// 方法2：同时拿到数组的下标索引和对应的值
	for index, value := range sli {
		fmt.Printf("slice index : %d,value : %d\n", index, value)
	}
}

/*
Channel 遍历的特点：
1.使用 range 遍历 channel 时，会一直等待新的数据

	只有当 channel 被关闭时，遍历才会结束
	如果 channel 没有被关闭，程序会一直阻塞在 range 语句处

2.正确的使用方式：

	需要有一个发送方（sender）向 channel 发送数据
	发送完所有数据后，需要调用 close(ch) 关闭 channel
	接收方（receiver）使用 range 来接收数据

3.注意事项：

	只有发送方才能关闭 channel，接收方不能关闭
	关闭一个已经关闭的 channel 会导致 panic
	向一个已关闭的 channel 发送数据也会导致 panic
*/
func traverseChannel(ch chan int) {
	// 启动一个 goroutine 来发送数据
	go func() {
		ch <- 1
		ch <- 2
		ch <- 3
		// 发送完数据后关闭 channel
		close(ch)
	}()

	// 使用 range 遍历 channel
	// 注意：这里会阻塞直到 channel 被关闭
	for value := range ch {
		fmt.Printf("从 channel 接收到的值: %d\n", value)
	}
}

func traverseMap(m map[string]string) {
	for key, value := range m {
		fmt.Printf("map key: %s, value: %s\n", key, value)
	}

	for key := range m {
		fmt.Printf("map key: %s, value: %s\n", key, m[key])
	}
}
